//
//  VPNManager.m
//  gdemm
//
//  Created by 乔明超 on 16/4/5.
//  Copyright © 2016年 Goldencis. All rights reserved.
//

#import "VPNManager.h"
#import <NetworkExtension/NEVPNManager.h>
#import <NetworkExtension/NEVPNProtocolIPSec.h>
#import <NetworkExtension/NEVPNConnection.h>
#import "UserDefaultsUtil.h"
@interface VPNManager()
@property (nonatomic,strong) NEVPNManager *vpnManager;
@property (nonatomic,assign) BOOL mDisable;
@end
@implementation VPNManager

- (NEVPNManager *)vpnManager{

    if (_vpnManager == nil) {
        _vpnManager = [NEVPNManager sharedManager];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vpnStatusDidChanged:) name:NEVPNStatusDidChangeNotification object:nil];
        
    }
    return _vpnManager;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        _mDisable = NO;
        
    }
    return self;
}
static VPNManager *_mInstance;

+ (instancetype)getInstance{

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _mInstance = [[self alloc]init];
    });
    return _mInstance;
}

- (NSString *)supportPolicy{
    return VPN;
}
- (BOOL)startPolicyWithPolicyType:(NSString *)policyType policyContent:(NSDictionary *)policyContent{

    _mDisable = YES;
    return YES;
}

- (BOOL)stopPolicyWithPolicyType:(NSString *)policyType{
    _mDisable = NO;
    [self disconnect];
    return YES;
}

- (BOOL)valid{
    return _mDisable;
}

- (void)run{
    [self connect];
    
}


#pragma mark VPN
- (void)connect{
    NEVPNStatus status = self.vpnManager.connection.status;
    if (status == NEVPNStatusInvalid || status == NEVPNStatusDisconnected || status == NEVPNStatusDisconnecting){
    
        [self installProfile];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vpnConfigDidChanged:) name:NEVPNConfigurationChangeNotification object:nil];
    }
    
    
    
}

- (void)disconnect{
     NEVPNStatus status = self.vpnManager.connection.status;
    if (status == NEVPNStatusConnected || status == NEVPNStatusConnecting || status == NEVPNStatusReasserting){
         [self.vpnManager.connection stopVPNTunnel];
    }
   
    
}

- (void)vpnConfigDidChanged:(NSNotification *)notification
{
    // TODO: Save configuration failed
    [self startConnecting];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NEVPNConfigurationChangeNotification
                                                  object:nil];
}

- (void)startConnecting
{
    NSError *startError;
    [self.vpnManager.connection startVPNTunnelAndReturnError:&startError];
    if (startError) {
        HRLog(@"Start VPN failed: [%@]", startError.localizedDescription);
    }else{
        
        HRLog(@"Connection established!");
    }
}
//VPN状态监听
- (void)vpnStatusDidChanged:(NSNotification *)notification
{
    NEVPNStatus status = self.vpnManager.connection.status;
    switch (status) {
        case NEVPNStatusConnected:
            HRLog(@"VPN连接成功");
            [[UserDefaultsUtil shareInstance]saveStringConfig:@"vpnStatus" :@"success"];
            break;
        case NEVPNStatusInvalid:
        case NEVPNStatusDisconnected:
            HRLog(@"VPN断开或无效");
            [[UserDefaultsUtil shareInstance]saveStringConfig:@"vpnStatus" :@"disconnect"];
            break;
        case NEVPNStatusConnecting:
            HRLog(@"连接中");
        case NEVPNStatusReasserting:
            HRLog(@"VPN重申");
            [[UserDefaultsUtil shareInstance]saveStringConfig:@"vpnStatus" :@"disconnect"];
            break;
        case NEVPNStatusDisconnecting:
            HRLog(@"VPN断开中");
            [[UserDefaultsUtil shareInstance]saveStringConfig:@"vpnStatus" :@"disconnect"];
            break;
        default:
            break;
    }
}



- (void)installProfile{
    NSString *server = [[UserDefaultsUtil shareInstance]getString:LC_SERVADDR];
    NSString *username = @"cis";
    
    
    [self createKeychainValue:@"hrjd" forIdentifier:@"VPN_PASSWORD"];
    [self createKeychainValue:@"psk123456" forIdentifier:@"PSK"];
    
    [self.vpnManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
        
        if (error) {
            HRLog(@"Load config failed [%@]",error.localizedDescription);
            return ;
        }
        NEVPNProtocolIPSec *p  = (NEVPNProtocolIPSec *)self.vpnManager.protocolConfiguration;
        
        if (p) {
            
        }else{
            
            p = [[NEVPNProtocolIPSec alloc]init];
        }
        
        p.username = username;
        p.serverAddress = server;
        p.passwordReference = [self searchKeychainCopyMatching:@"VPN_PASSWORD"];
        p.sharedSecretReference = [self searchKeychainCopyMatching:@"PSK"];
        
        p.authenticationMethod =  NEVPNIKEAuthenticationMethodSharedSecret;
        p.useExtendedAuthentication = YES;
        p.disconnectOnSleep = NO;
        self.vpnManager.protocolConfiguration = p;
        self.vpnManager.localizedDescription = @"hrjd";
        self.vpnManager.enabled = YES;
        [self.vpnManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
            if (error) {
                HRLog(@"save config failed [%@]",error.localizedDescription);
            }
            
        }];
    }];
}

#pragma mark - KeyChain

static NSString * const serviceName = @"im.zorro.ipsec_demo.vpn_config";


- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
    
    NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
    [searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
    [searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
    [searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
    [searchDictionary setObject:serviceName forKey:(__bridge id)kSecAttrService];
    
    return searchDictionary;
}

- (NSData *)searchKeychainCopyMatching:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
    
    // Add search attributes
    [searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    
    // Add search return types
    // Must be persistent ref !!!!
    [searchDictionary setObject:@YES forKey:(__bridge id)kSecReturnPersistentRef];
    
    CFTypeRef result = NULL;
    SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &result);
    
    return (__bridge_transfer NSData *)result;
}

- (BOOL)createKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
    NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
    
    OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dictionary);
    
    NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
    [dictionary setObject:passwordData forKey:(__bridge id)kSecValueData];
    
    status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
    
    if (status == errSecSuccess) {
        return YES;
    }
    return NO;
}


@end
